package portal.manager.tracker;

import java.io.CharArrayReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.osgi.framework.BundleContext;
import org.osgi.framework.Filter;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;

import portal.manager.impl.PortalPanelImpl;
/**
 * 
 * @author Sorrentino
 *
 */
public class PortalPanelTracker extends ServiceTracker {


	Logger logger = Logger.global;
	
	/**
	 * 
	 * @param context
	 * @return
	 * @throws Exception
	 */
	static public ServiceTracker createPortalPanelTracker( BundleContext context ) throws Exception {
		final String assertMsg = "param context is null!";
		
		assert null!=context: assertMsg;
		
		if( null==context ) throw new IllegalArgumentException(assertMsg);
		
		Filter filter = context.createFilter("(bind.protocol=panel)");
		
		return new PortalPanelTracker( context, filter, null );
	}

	/**
	 * 
	 * @param context
	 */
	protected PortalPanelTracker(BundleContext context, Filter filter, ServiceTrackerCustomizer customizer) {
		super(context, filter, customizer);
	}

	/**
	 * 
	 * @param panel
	 * @return
	 * @throws Exception
	 */
	private CharSequence getPanelContent( Reader r ) throws Exception {

		java.io.BufferedReader br = new java.io.BufferedReader(r, 4096);
		
		StringBuilder sb = new StringBuilder();
		
		for( int c;  (c = br.read())!=-1 ; sb.append((char)c) );

		return sb.toString();
	}

	
	/**
	 * 
	 * @param service
	 * @param m
	 * @param anno
	 * @return
	 * @throws Exception 
	 */
	private portal.PortalPanel createPortalPanel( Object service, Method method, portal.annotations.PortalPanel anno ) throws Exception {
			
			Object content = method.invoke(service);
			if( null==content ) {
				final String msg = MessageFormat.format("content of portal panel {0} is null", anno);
				logger.severe(msg);
				throw new Exception( msg );
			}
			
			CharSequence buffer = null;
			
			if( content instanceof CharSequence ) {
				buffer = (CharSequence) content;
			}
			else if( content instanceof Reader ) {
				buffer = getPanelContent((Reader)content);
			}
			else if( content instanceof InputStream ) {
				buffer = getPanelContent( new InputStreamReader((InputStream)content) );
			}
			else {
				final String msg = MessageFormat.format("illegal panel's content type {0}", content.getClass().getName() );
				logger.severe(msg);
				throw new Exception( msg );
			}
			
			Reader reader = new CharArrayReader( buffer.toString().toCharArray() );
			
			return new PortalPanelImpl( anno.name(), anno.codeModule(), reader );
		
	}

	/**
	 * 
	 */
	@Override
	public Object addingService(ServiceReference reference) {
		Object service = super.addingService(reference);
		
		Class<?> clazz = service.getClass();
				
		for( Method method : clazz.getDeclaredMethods() ) {
		
			portal.annotations.PortalPanel anno = method.getAnnotation( portal.annotations.PortalPanel.class);
			
			if( null!=anno ) {
				
				try {
					portal.PortalPanel panel = createPortalPanel(service, method, anno);
					
					Dictionary<String,Object> serviceProps = new Hashtable<String,Object>(1);
					
					serviceProps.put( "bind.name", anno.name() );
					
					// register the service
					context.registerService(
							portal.PortalPanel.class.getName(), 
							panel,
							serviceProps
							);
					
				} catch (Exception e) {
					
					logger.log( Level.WARNING, "erron on publication of service {0}", anno );
				}
			}
		}

		return service;
	}

	/**
	 * 
	 */
	@Override
	public void removedService(ServiceReference reference, Object service) {
		super.removedService(reference, service);
	}


}
